package com.shen.library_nettysocket.server

import io.netty.channel.EventLoopGroup
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioServerSocketChannel
import io.netty.channel.ChannelInitializer
import io.netty.handler.codec.LengthFieldPrepender
import io.netty.handler.codec.LengthFieldBasedFrameDecoder
import io.netty.handler.codec.protobuf.ProtobufDecoder
import com.shen.library_nettysocket.protobuf.MessageProtobuf
import io.netty.handler.codec.protobuf.ProtobufEncoder
import io.netty.bootstrap.ServerBootstrap
import io.netty.channel.ChannelOption
import io.netty.channel.socket.SocketChannel
import java.lang.Exception

object NettyServerDemo {
    @JvmStatic
    fun main(args: Array<String>) {

        /** boss线程 -- 「监听·端口」 */
        val boss: EventLoopGroup = NioEventLoopGroup()
        /** worker线程 -- 负责「数据·读写」 */
        val worker: EventLoopGroup = NioEventLoopGroup()

        try {
            val bootstrap = ServerBootstrap()                                       // 辅助「启动类」

            bootstrap.group(boss, worker)                                           // 设置「线程池」
            bootstrap.channel(NioServerSocketChannel::class.java)                   // 设置「socket工厂」
            bootstrap.childHandler(object : ChannelInitializer<SocketChannel>() {   // 设置「管道工厂」
                @Throws(Exception::class)
                override fun initChannel(socketChannel: SocketChannel) {
                    val pipeline = socketChannel.pipeline()             // 获取管道

                    pipeline.addLast("frameEncoder", LengthFieldPrepender(2))
                    pipeline.addLast("frameDecoder", LengthFieldBasedFrameDecoder(
                            65535, 0, 2, 0, 2))

                    pipeline.addLast(ProtobufDecoder(MessageProtobuf.Msg.getDefaultInstance()))
                    pipeline.addLast(ProtobufEncoder())

                    pipeline.addLast(ServerHandler())                   // 处理类
                }
            })

            /* 设置TCP参数 */
            bootstrap.option(ChannelOption.SO_BACKLOG, 1024)                  // 设置链接「缓冲池的大小」（ServerSocketChannel的设置）
            bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true)           // 维持「链接的活跃」，清除「死链接」(SocketChannel的设置)
            bootstrap.childOption(ChannelOption.TCP_NODELAY, true)            // 关闭「延迟发送」

            val future = bootstrap.bind(8855).sync()                        // 绑定端口
            println("server start ...... ")
            future.channel().closeFuture().sync()                                   // 等待「服务端·监听端口·关闭」

        } catch (e: InterruptedException) {
            e.printStackTrace()

        } finally {
            //优雅退出，释放线程池资源
            boss.shutdownGracefully()
            worker.shutdownGracefully()
        }
    }
}